#ifndef __ETLLIST_H__
#define __ETLLIST_H__

#ifndef __ETL_H__
	#error etllist.h requires etl.h to be included first
#endif

#ifndef __ETLALLOC_H__
	#error etllist.h requires etlalloc.h to be included first
#endif

//namespace ETL_ListHelper
//{

#pragma warning( push )
#pragma warning(disable : 4786)

template <class T, int rowCount = 16>
class chObjList : protected chHashAlloc<hash_node<T>, rowCount>
{
	typedef hash_node<T>							type_hash_node;
	typedef chHashAlloc<type_hash_node, rowCount>	type_nodeHashAlloc;
public:
	typedef hash_iterator<T>					iterator;
public:
	iterator begin()
	{ return iterator(m_vRootNode.pNext); }
	iterator end()
	{ return iterator(&m_vRootNode); }
	int size() const
	{ return m_nElementCount; }
	
	// element operactor
	void push_back(const T& tObj)
	{ push_back(T(tObj)); }
	void push_back(T& tObj)
	{ InsertNode(*m_vRootNode.pPrev, tObj, m_vRootNode); }
	
	void push_front(const T& tObj)
	{ push_front(T(tObj)); }
	void push_front(T& tObj)
	{ InsertNode(m_vRootNode, tObj, *m_vRootNode.pNext); }
	
	iterator insert(iterator it, const T& tObj)
	{ return insert(it, T(tObj)); }
	iterator insert(iterator it, T& tObj)
	{
		chASSERT(it.pThisNode != NULL);
		return InsertNode(*it.pThisNode->pPrev, tObj, *it.pThisNode);
	}

	void pop_back()
	{ RemoveNode(*m_vRootNode.pPrev); }
	void pop_front()
	{ RemoveNode(*m_vRootNode.pNext); }
	T& back() const
	{
		chASSERT(!empty());
		return m_vRootNode.pPrev->vData;
	}
	T& front() const
	{
		chASSERT(!empty());
		return m_vRootNode.pNext->vData;
	}
	iterator find(const T& tObj)
	{
		type_hash_node* pNode = m_vRootNode.pNext;
		for(; pNode != &m_vRootNode; pNode = pNode->pNext)
		{
			if(pNode->vData == tObj)
				break;
		}
		return iterator(pNode);
	}
	bool empty() const
	{
		return m_nElementCount == 0;
	}
	iterator erase(iterator it)
	{
		chASSERT(it.pThisNode != NULL);
		iterator itDel(it.pThisNode->pPrev);
		RemoveNode(*it.pThisNode);
		return itDel;
	}
	void clear()
	{
		while(m_vRootNode.pPrev != &m_vRootNode)
			RemoveNode(*m_vRootNode.pPrev);
	}

	chObjList& operator = (chObjList& srcList)
	{
		clear();
		iterator it = srcList.begin();
		for(; it != srcList.end(); it ++)
			push_back(*it);
		return *this;
	}
	void RemoveAll() // remove all alloc data
	{
		clear();
		type_nodeHashAlloc::FreeAll();
	}	
	iterator AllocPushFront()
	{
		return AllocInsertAt(begin());
	}
	iterator AllocPushBack()
	{
		return AllocInsertAt(end());
	}
	iterator AllocInsertAt(iterator it)
	{
		type_hash_node& rHead = *it.pThisNode->pPrev;
		type_hash_node& rTail = *it.pThisNode;

		m_nElementCount ++;
		type_hash_node& rNode = type_nodeHashAlloc::BorrowObject();
//		ConstructObjects<T, false>(&rNode.vData, 1);

		rHead.pNext = &rNode;
		rNode.pNext = &rTail;
		rNode.pPrev = &rHead;
		rTail.pPrev = &rNode;
		return iterator(&rNode);
	}
private:
	iterator InsertNode(type_hash_node& rHead, T& tObj, type_hash_node& rTail)
	{
		m_nElementCount ++;
		type_hash_node& rNode = type_nodeHashAlloc::BorrowObject();
//		ConstructObjects<T, false>(&rNode.vData, 1);
		rNode.vData = tObj;

		rHead.pNext = &rNode;
		rNode.pNext = &rTail;
		rNode.pPrev = &rHead;
		rTail.pPrev = &rNode;
		return iterator(&rNode);
	}
	void RemoveNode(type_hash_node& rRemove)
	{
		chASSERT(!empty() && (&rRemove != &m_vRootNode));

		m_nElementCount --;
		rRemove.pPrev->pNext = rRemove.pNext;
		rRemove.pNext->pPrev = rRemove.pPrev;
		rRemove.pNext = rRemove.pPrev = NULL;
//		DestructObjects<T, false>(&rRemove.vData, 1);
		type_nodeHashAlloc::ReturnObject(rRemove);
	}
public:
	chObjList() : m_nElementCount(0)
	{
		m_vRootNode.pNext = &m_vRootNode;
		m_vRootNode.pPrev = &m_vRootNode;
	}
//	chObjList(const T* pData, int nSize) : m_nElementCount(0)
//	{
//		chASSERT(pData != NULL && nSize > 0);
//		for(int i = 0; i < nSize; i++)
//			push_back(pData[i]);
//	}
	chObjList(chObjList& srcArray) : m_nElementCount(0)
	{
		m_vRootNode.pNext = &m_vRootNode;
		m_vRootNode.pPrev = &m_vRootNode;
		operator = (srcArray);
	}
	~chObjList() { clear(); }
protected:
	int			m_nElementCount;
	type_hash_node	m_vRootNode;
};

#pragma warning( pop )
//};
//using namespace ETL_ListHelper;

#endif //__ETLLIST_H__
